home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 722 / 722.xpi / chrome / noscript.jar / content / noscript / STS.js < prev    next >
Text File  |  2010-02-12  |  6KB  |  233 lines

  1. // http://lists.w3.org/Archives/Public/www-archive/2009Sep/att-0051/draft-hodges-strict-transport-sec-05.plain.html
  2.  
  3. const STS = {
  4.   
  5.   enabled: true,
  6.   
  7.   get db() {
  8.     delete this.db;
  9.     return this.initPersistentDB();
  10.   },
  11.   
  12.   initPersistentDB: function() {
  13.     return this.db = new STSDB(STSPersistence);
  14.   },
  15.   
  16.   processRequest: function(chan) {
  17.     if (this.enabled) {
  18.       var uri = chan.URI;
  19.       if (uri.schemeIs("https")) {
  20.         try {
  21.           this.db.processHeader(uri.asciiHost, chan.getResponseHeader("Strict-Transport-Security"));
  22.         } catch (e) {
  23.           try {
  24.             this.db.processHeader(uri.asciiHost, chan.getResponseHeader("X-Strict-Transport-Security"));
  25.           } catch (e) {}
  26.         }
  27.       }
  28.     }
  29.   },
  30.   
  31.   isSTSURI: function(uri) {
  32.     return this.enabled && this.db.matches(uri.asciiHost);
  33.   },
  34.   
  35.   enterPrivateBrowsing: function() {
  36.     try {
  37.       this.db.save();
  38.     } catch(e) {}
  39.     
  40.     this.db = new STSDB(this.db);
  41.   },
  42.   
  43.   exitPrivateBrowsing: function() {
  44.     this.initPersistentDB();
  45.   },
  46.   
  47.   eraseDB: function() {
  48.     this.db.reset();
  49.     STSPersistence.save(this.db);
  50.   },
  51.   
  52.   patchErrorPage: function(docShell, errorURI) {
  53.     // see #errors-in-secure-transport-establishment
  54.     if (!this.enabled) return;
  55.     
  56.     if (!(/^about:certerror?/.test(errorURI.spec) &&
  57.           this.isSTSURI(docShell.currentURI))
  58.        ) return;
  59.     
  60.     Thread.delay(function() {
  61.       docShell.document.getElementById("expertContent").style.display = "none";
  62.     }, 100);
  63.   },
  64.   
  65.   dispose: function() {
  66.     this.db.save();
  67.   }
  68. };
  69.  
  70. function STSDB(source) {
  71.   this._entries = {};
  72.   if (source && source._entries) { // clone
  73.     var entries = source._entries;
  74.     for (var p in entries) {
  75.       this._entries[p] = entries[p];
  76.     }
  77.   } else {
  78.     if (source && source.load) {
  79.       this._persistence = source;
  80.       this.load();
  81.     }
  82.   } 
  83. }
  84.  
  85. STSDB.prototype = {
  86.   _persistence: null,
  87.   _dirty: false,
  88.   _saveTimer: null,
  89.   
  90.   processHeader: function(host, header) {
  91.     if (DNS.isIP(host)) return;
  92.     
  93.     var m = header.match(/^\s*max-age\s*=\s*(\d+)\s*(;\s*includeSubDomains)?/i);
  94.     if (!m) return;
  95.     var maxAge = parseInt(m[1]);
  96.     var includeSubDomains = !!m[2];
  97.     var expiration = Math.round(Date.now() / 1000) + maxAge; 
  98.     if (host in this._entries) {
  99.       var e = this._entries[host];
  100.       if (e.expiration == expiration && e.includeSubDomains == includeSubDomains)
  101.         return;
  102.       
  103.       e.expiration = expiration;
  104.       e.includeSubDomains = includeSubDomains;
  105.     } else {
  106.       this.add(new STSEntry(host, expiration, includeSubDomains));
  107.     }
  108.     this.saveDeferred();
  109.   },
  110.   
  111.   add: function(entry) {
  112.     this._entries[entry.host] = entry;
  113.   },
  114.   
  115.   matches: function(host, asSuperDomain) {
  116.     if (host in this._entries) {
  117.       var e = this._entries[host];
  118.       
  119.       if (e.expiration >= Date.now() / 1000) {
  120.         if ((!asSuperDomain || e.includeSubDomains))
  121.           return true;
  122.       } else {
  123.         delete this._entries[host];
  124.       }
  125.     }
  126.     
  127.     var dotPos = host.indexOf(".");
  128.     var lastDotPos = host.lastIndexOf(".");
  129.     
  130.     if (dotPos == lastDotPos)
  131.       return false;
  132.     
  133.     return this.matches(host.substring(dotPos + 1), true);
  134.   },
  135.   
  136.   serialize: function() {
  137.     var lines = [], ee = this._entries;
  138.     var e;
  139.     for (var h in ee) {
  140.       e = ee[h];
  141.       lines.push([e.host, e.expiration, e.includeSubDomains ? "*" : ""].join(";"));
  142.     }
  143.     return lines.join("\n");
  144.   },
  145.   restore: function(s) {
  146.     s.split(/\s+/).forEach(function(line) {
  147.       if (line) {
  148.         var args = line.split(";");
  149.         if (args.length > 1)
  150.           this.add(new STSEntry(args[0], parseInt(args[1]), !!args[2]));
  151.       }
  152.     }, this);
  153.   },
  154.   
  155.   load: function() {
  156.     if (this._persistence) {
  157.       this._persistence.load(this);
  158.       this.purgeExpired();
  159.     }
  160.   },
  161.   
  162.   save: function() {
  163.     if (this._dirty && this._persistence) {
  164.       this.purgeExpired();
  165.       this._persistence.save(this);
  166.       this._dirty = false;
  167.     }
  168.   },
  169.   
  170.   saveDeferred: function() {
  171.     if (this._dirty || !this._persistence) return;
  172.     this._dirty = true;
  173.     if (!this._timer) this._timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
  174.     this._timer.initWithCallback(this, 10000, CI.nsITimer.TYPE_ONE_SHOT);
  175.   },
  176.   notify: function(timer) {
  177.     this.save();
  178.   },
  179.   
  180.   purgeExpired: function() {
  181.     var now = Math.round(Date.now() / 1000);
  182.     for (var h in this._entries) {
  183.       if (this._entries[h].expiration < now) delete this._entries[h];
  184.     }
  185.   },
  186.   
  187.   reset: function() {
  188.     this._entries = {};
  189.     this._dirty = false;
  190.   }
  191. };
  192.  
  193. function STSEntry(host, expiration, includeSubDomains) {
  194.   this.host = host;
  195.   this.expiration = expiration;
  196.   if (includeSubDomains) this.includeSubDomains = includeSubDomains;
  197. }
  198.  
  199. STSEntry.prototype = {
  200.   includeSubDomains: false
  201. };
  202.  
  203.  
  204. const STSPersistence = {
  205.   get _file() {
  206.     delete this._file;
  207.     var f =  CC["@mozilla.org/file/directory_service;1"].getService(
  208.         CI.nsIProperties).get("ProfD", CI.nsIFile);
  209.     f.append("NoScriptSTS.db");
  210.     return this._file = f;
  211.   },
  212.   load: function(db) {
  213.     var f = this._file;
  214.     try {
  215.       if (f.exists()) db.restore(IO.readFile(f));
  216.     } catch (e) {
  217.       dump("STS: Error loading db from " + f.path + "!" + e + "\n");
  218.       return false;
  219.     }
  220.     return true;
  221.   },
  222.   save: function(db) {
  223.     f = this._file;
  224.     try {
  225.       IO.safeWriteFile(f, db.serialize());
  226.     } catch(e) {
  227.       dump("STS: Error saving db to " + f.path + "!" + e + "\n");
  228.       return false;
  229.     }
  230.     return true;
  231.   }
  232. };
  233.